use smcrypto::sm4;
use udf::prelude::*;


struct UdfSm4Encode;

#[register(name = "udf_sm4_encode")]
impl BasicUdf for UdfSm4Encode {
    // Specify return type of this UDF to be a nullable integer
    type Returns<'a> = Option<String>;

    // Perform initialization steps here
    fn init(cfg: &UdfCfg<Init>, args: &ArgList<Init>) -> Result<Self, String> {
        Ok(Self)
    }

    // Create a result here
    fn process<'a>(
        &'a mut self,
        cfg: &UdfCfg<Process>,
        args: &ArgList<Process>,
        error: Option<NonZeroU8>,
    ) -> Result<Self::Returns<'a>, ProcessError> {
        match args.get(0) {
            None => {
                Ok(None)
            }
            Some(a) => {
                match a.value() {
                    SqlResult::String(Some(buf)) => {
                        Ok(Sm4Util::encode_no_secret(buf))
                    }
                    _ => Ok(None)
                }
            }
        }
    }
}


struct UdfSm4Decode;
#[register(name = "udf_sm4_decode")]
impl BasicUdf for UdfSm4Decode {
    // Specify return type of this UDF to be a nullable integer
    type Returns<'a> = Option<String>;

    // Perform initialization steps here
    fn init(cfg: &UdfCfg<Init>, args: &ArgList<Init>) -> Result<Self, String> {
        Ok(Self)
    }

    // Create a result here
    fn process<'a>(
        &'a mut self,
        cfg: &UdfCfg<Process>,
        args: &ArgList<Process>,
        error: Option<NonZeroU8>,
    ) -> Result<Self::Returns<'a>, ProcessError> {
        match args.get(0) {
            None => {
                Ok(None)
            }
            Some(a) => {
                match a.value() {
                    SqlResult::String(Some(buf)) => {
                        Ok(Sm4Util::decode_no_secret(buf))
                    }
                    _ => Ok(None)
                }
            }
        }
    }
}


struct Sm4Util;

impl Sm4Util {
    /**
    * sm4加密
    */
    fn encode_no_secret<'a>(data: &'a [u8]) -> Option<String> {
        let key = SecretConfig::secret().as_bytes();
        let sm4_ecb = sm4::CryptSM4ECB::new(key);

        //sm4 加密
        let enc_ecb = sm4_ecb.encrypt_ecb(data);

        //转换为16进制字符串
        Some(hex::encode(enc_ecb))
    }
    /**
    * sm4解密
    */
    fn decode_no_secret<'a>(data: &'a [u8]) -> Option<String> {
        let key = SecretConfig::secret().as_bytes();
        let sm4_ecb = sm4::CryptSM4ECB::new(key);

        //16进制转换为vec<u8>
        match hex::decode(data) {
            Err(_) => None,
            Ok(hex_bytes) => {
                let decrypt_vec = sm4_ecb.decrypt_ecb(&hex_bytes);
                match String::from_utf8(decrypt_vec) {
                    Err(_) => None,
                    Ok(decrypt_string) => Some(decrypt_string)
                }
            }
        }
    }
}


struct SecretConfig;
impl SecretConfig {
    /**
    * 秘钥：要求16位的字符串
    */
    fn secret<'a>() -> &'a str {
        "f3a4c2d1e09f7b65"
    }

    /**
    * 偏移向量
    */
    fn iv<'a>() -> &'a str {
        "1234567890ABCDEF"
    }
}


